<!doctype html>
<html>
<head>
<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>
<title>计算机组成原理笔记.md</title><style type='text/css'>html, body {overflow-x: initial !important;}.CodeMirror { height: auto; }
.CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; }
.CodeMirror-lines { padding: 4px 0px; }
.CodeMirror pre { }
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; }
.CodeMirror-gutters { border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); background-color: rgb(247, 247, 247); white-space: nowrap; }
.CodeMirror-linenumbers { }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
.CodeMirror div.CodeMirror-cursor { border-left-width: 1px; border-left-style: solid; border-left-color: black; z-index: 3; }
.CodeMirror div.CodeMirror-secondarycursor { border-left-width: 1px; border-left-style: solid; border-left-color: silver; }
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0px; background-color: rgb(119, 238, 119); z-index: 1; background-position: initial initial; background-repeat: initial initial; }
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite { }
.cm-tab { display: inline-block; }
.cm-s-typora-default .cm-header, .cm-s-typora-default .cm-property { color: rgb(217, 79, 138); }
.cm-s-typora-default pre.cm-header1:not(.cm-atom) :not(.cm-overlay) { font-size: 2rem; line-height: 2rem; }
.cm-s-typora-default pre.cm-header2:not(.cm-atom) :not(.cm-overlay) { font-size: 1.4rem; line-height: 1.4rem; }
.cm-s-typora-default .cm-atom, .cm-s-typora-default .cm-number { color: rgb(149, 132, 134); }
.cm-s-typora-default .cm-table-row, .cm-s-typora-default .cm-block-start { font-family: monospace; }
.cm-s-typora-default .cm-comment, .cm-s-typora-default .cm-code { color: rgb(74, 90, 159); font-family: monospace; }
.cm-s-typora-default .cm-tag { color: rgb(169, 68, 66); }
.cm-s-typora-default .cm-string { color: rgb(126, 134, 169); }
.cm-s-typora-default .cm-link { color: rgb(196, 122, 15); text-decoration: underline; }
.cm-s-typora-default .cm-variable-2, .cm-s-typora-default .cm-variable-1 { color: inherit; }
.cm-s-typora-default .cm-overlay { font-size: 1rem; font-family: monospace; }
.CodeMirror.cm-s-typora-default div.CodeMirror-cursor { border-left-width: 3px; border-left-style: solid; border-left-color: rgb(228, 98, 154); }
.cm-s-typora-default .CodeMirror-activeline-background { left: -60px; right: -30px; background-color: rgba(204, 204, 204, 0.2); background-position: initial initial; background-repeat: initial initial; }
.cm-s-typora-default .CodeMirror-gutters { border-right-style: none; background-color: inherit; }
.cm-s-typora-default .cm-trailing-space-new-line::after, .cm-startspace::after, .cm-starttab .cm-tab::after { content: '•'; position: absolute; left: 0px; opacity: 0; font-family: LetterGothicStd, monospace; }
.os-windows .cm-startspace::after, .os-windows .cm-starttab .cm-tab::after { left: -0.1em; }
.cm-starttab .cm-tab::after { content: ' '; }
.cm-startspace, .cm-tab, .cm-starttab, .cm-trailing-space-a, .cm-trailing-space-b, .cm-trailing-space-new-line { font-family: monospace; position: relative; }
.cm-s-typora-default .cm-trailing-space-new-line::after { content: '↓'; opacity: 0.3; }
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
.cm-s-inner .cm-variable { color: black; }
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-inner .cm-property { color: black; }
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: blue; }
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: bold; }
.cm-del { text-decoration: line-through; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-error { color: rgb(255, 0, 0); }
.cm-invalidchar { color: rgb(255, 0, 0); }
.cm-constant { color: rgb(38, 139, 210); }
.cm-defined { color: rgb(181, 137, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.cm-s-inner .CodeMirror-activeline-background { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit inherit; background-repeat: inherit inherit; }
.CodeMirror { position: relative; overflow: hidden; }
.CodeMirror-scroll { margin-bottom: -30px; margin-right: -30px; padding-bottom: 30px; padding-right: 30px; height: 100%; outline: none; position: relative; box-sizing: content-box; }
.CodeMirror-sizer { position: relative; }
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow-x: hidden; overflow-y: scroll; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow-y: hidden; overflow-x: scroll; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border-width: 0px; background-color: transparent; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; word-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; background-position: initial initial; background-repeat: initial initial; }
.CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right-width: 30px; border-right-style: solid; border-right-color: transparent; width: -webkit-fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right-style: none; width: auto; }
.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-widget { }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right-style: none; width: 0px; }
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
.CodeMirror-selected { background-color: rgb(217, 217, 217); background-position: initial initial; background-repeat: initial initial; }
.CodeMirror-focused .CodeMirror-selected { background-color: rgb(215, 212, 240); background-position: initial initial; background-repeat: initial initial; }
.cm-searching { background-color: rgba(255, 255, 0, 0.4); background-position: initial initial; background-repeat: initial initial; }
.CodeMirror span { }
@media print { 
  .CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}
.CodeMirror-lint-markers { width: 16px; }
.CodeMirror-lint-tooltip { background-color: infobackground; border: 1px solid black; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; color: infotext; font-family: monospace; overflow: hidden; padding: 2px 5px; position: fixed; white-space: pre-wrap; z-index: 10000; max-width: 600px; opacity: 0; transition: opacity 0.4s; font-size: 0.8em; }
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat no-repeat; }
.CodeMirror-lint-mark-error { background-image: url(); }
.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { cursor: pointer; display: inline-block; height: 16px; width: 16px; vertical-align: middle; position: relative; background-position: center center; background-repeat: no-repeat no-repeat; }
.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { padding-left: 18px; background-position: left top; background-repeat: no-repeat no-repeat; }
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { background-image: url(); }
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url(); }
.CodeMirror-lint-marker-multiple { background-image: url(); width: 100%; height: 100%; background-position: right bottom; background-repeat: no-repeat no-repeat; }


html { font-size: 14px; background-color: rgb(255, 255, 255); color: rgb(51, 51, 51); }
body { margin: 0px; padding: 0px; height: auto; bottom: 0px; top: 0px; left: 0px; right: 0px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 1rem; line-height: 1.42857143; overflow-x: hidden; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit inherit; background-repeat: inherit inherit; }
a:active, a:hover { outline: 0px; }
.in-text-selection, ::selection { background-color: rgb(181, 214, 252); text-shadow: none; background-position: initial initial; background-repeat: initial initial; }
#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; padding-bottom: 70px; white-space: pre-wrap; overflow-x: auto; }
.for-image #write { padding-left: 8px; padding-right: 8px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
@media screen and (max-width: 500px) { 
  body.typora-export { padding-left: 0px; padding-right: 0px; }
  .CodeMirror-sizer { margin-left: 0px !important; }
  .CodeMirror-gutters { display: none !important; }
}
.typora-export #write { margin: 0px auto; }
#write > p:first-child, #write > ul:first-child, #write > ol:first-child, #write > pre:first-child, #write > blockquote:first-child, #write > div:first-child, #write > table:first-child { margin-top: 30px; }
#write li > table:first-child { margin-top: -20px; }
img { max-width: 100%; vertical-align: middle; }
input, button, select, textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; line-height: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
::before, ::after, * { box-sizing: border-box; }
#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write div, #write pre { width: inherit; }
#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6 { position: relative; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
p { -webkit-margin-before: 1rem; -webkit-margin-after: 1rem; -webkit-margin-start: 0px; -webkit-margin-end: 0px; }
.mathjax-block { margin-top: 0px; margin-bottom: 0px; -webkit-margin-before: 0rem; -webkit-margin-after: 0rem; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: bold; font-style: italic; }
a { cursor: pointer; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; margin: 4px 0px 0px; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
table.md-table td { min-width: 80px; }
.CodeMirror-gutters { border-right-width: 0px; background-color: inherit; }
.CodeMirror { text-align: left; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
pre { white-space: pre-wrap; }
.CodeMirror-gutters { margin-right: 4px; }
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; position: relative !important; background-position: inherit inherit; background-repeat: inherit inherit; }
.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
.md-fences .CodeMirror.CodeMirror-wrap { top: -1.6em; margin-bottom: -1.6em; }
.md-fences.mock-cm { white-space: pre-wrap; }
.show-fences-line-number .md-fences { padding-left: 0px; }
.show-fences-line-number .md-fences.mock-cm { padding-left: 40px; }
.footnotes { opacity: 0.8; font-size: 0.9rem; padding-top: 1em; padding-bottom: 1em; }
.footnotes + .footnotes { margin-top: -1em; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background-color: transparent; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; line-height: normal; font-weight: normal; text-align: left; box-sizing: content-box; direction: ltr; background-position: initial initial; background-repeat: initial initial; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li p, li .mathjax-block { margin: 0.5rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; }
@media print { 
  html, body { height: 100%; }
  .typora-export * { -webkit-print-color-adjust: exact; }
  h1, h2, h3, h4, h5, h6 { break-after: avoid-page; orphans: 2; }
  p { orphans: 4; }
  html.blink-to-pdf { font-size: 13px; }
  .typora-export #write { padding-left: 1cm; padding-right: 1cm; }
  .typora-export #write::after { height: 0px; }
  @page { margin: 20mm 0mm; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
pre.md-meta-block { font-size: 0.8rem; min-height: 2.86rem; white-space: pre-wrap; background-color: rgb(204, 204, 204); display: block; overflow-x: hidden; background-position: initial initial; background-repeat: initial initial; }
p .md-image:only-child { display: inline-block; width: 100%; text-align: center; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.mathjax-block { white-space: pre; overflow: hidden; width: 100%; }
p + .mathjax-block { margin-top: -1.143rem; }
.mathjax-block:not(:empty)::after { display: none; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: none; box-shadow: none; }
.task-list { list-style-type: none; }
.task-list-item { position: relative; padding-left: 1em; }
.task-list-item input { position: absolute; top: 0px; left: 0px; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc::after, .md-toc-content::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); text-decoration: none; }
.md-toc-inner:hover { }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: bold; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) { 
  .md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
  .md-toc-h4 .md-toc-inner { margin-left: 5em; }
  .md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
  .md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: '.'; }
.md-tag { opacity: 0.5; }
.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: monospace; }
code { text-align: left; }
h1 .md-tag, h2 .md-tag, h3 .md-tag, h4 .md-tag, h5 .md-tag, h6 .md-tag { font-weight: initial; opacity: 0.35; }
a.md-print-anchor { border: none !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: none !important; background-color: transparent !important; text-shadow: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; }
.md-inline-math .MathJax_SVG .noError { display: none !important; }
.mathjax-block .MathJax_SVG_Display { text-align: center; margin: 1em 0em; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; display: block !important; }
.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }
.MathJax_SVG .MJX-monospace { font-family: monospace; }
.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }
.MathJax_SVG { display: inline; font-style: normal; font-weight: normal; line-height: normal; zoom: 90%; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; }
.MathJax_SVG * { transition: none; }


html {
	font-size: 19px;
}

html, body {
	margin: auto;
	background: #fefefe;
}
body {
	font-family: "Vollkorn", Palatino, Times;
	color: #333;
	line-height: 1.4;
	text-align: justify;
}
#write {
	max-width: 960px;
	margin: 0 auto;
	margin-bottom: 2em;
	line-height: 1.53;
}

#write>h2:first-child,
#write>h3:first-child,
#write>h4:first-child,
#write>p:first-child{
	margin-top: 1.2em;
}

/* Typography
-------------------------------------------------------- */

#write>h1:first-child,
h1 {
	margin-top: 1.6em;
	font-weight: normal;
}

h1 {
	font-size:3em;
}

h2 {
	margin-top:2em;
	font-weight: normal;
}

h3 {
	font-weight: normal;
	font-style: italic;
	margin-top: 3em;
}

h1, 
h2, 
h3{
	text-align: center;
}

h2:after{
	border-bottom: 1px solid #2f2f2f;
    content: '';
    width: 100px;
    display: block;
    margin: 0 auto;
    height: 1px;
}

h1+h2, h2+h3 {
	margin-top: 0.83em;
}

p,
.mathjax-block {
	margin-top: 0;
	-webkit-hypens: auto;
	-moz-hypens: auto;
	hyphens: auto;
}
ul {
	list-style: square;
	padding-left: 1.2em;
}
ol {
	padding-left: 1.2em;
}
blockquote {
	margin-left: 1em;
	padding-left: 1em;
	border-left: 1px solid #ddd;
}
code,
pre {
	font-family: "Consolas", "Menlo", "Monaco", monospace, serif;
	font-size: .9em;
	background: white;
}
.md-fences{
	margin-left: 1em;
	padding-left: 1em;
	border: 1px solid #ddd;
	padding-bottom: 8px;
	padding-top: 6px;
	margin-bottom: 1.5em;
}

a {
	color: #2484c1;
	text-decoration: none;
}
a:hover {
	text-decoration: underline;
}
a img {
	border: none;
}
h1 a,
h1 a:hover {
	color: #333;
	text-decoration: none;
}
hr {
	color: #ddd;
	height: 1px;
	margin: 2em 0;
	border-top: solid 1px #ddd;
	border-bottom: none;
	border-left: 0;
	border-right: 0;
}
.md-table-edit {
	background: #ededed;
    padding-top: 4px;
}
table {
	margin-bottom: 1.333333rem
}
table th,
table td {
	padding: 8px;
	line-height: 1.333333rem;
	vertical-align: top;
	border-top: 1px solid #ddd
}
table th {
	font-weight: bold
}
table thead th {
	vertical-align: bottom
}
table caption+thead tr:first-child th,
table caption+thead tr:first-child td,
table colgroup+thead tr:first-child th,
table colgroup+thead tr:first-child td,
table thead:first-child tr:first-child th,
table thead:first-child tr:first-child td {
	border-top: 0
}
table tbody+tbody {
	border-top: 2px solid #ddd
}

.task-list{
	padding:0;
}

.task-list-item {
	padding-left: 1.6rem;
}

.task-list-item input:before {
	content: '\221A';
	display: inline-block;
	width: 1.33333333rem;
  	height: 1.6rem;
	vertical-align: middle;
	text-align: center;
	color: #ddd;
	background-color: #fefefe;
}

.task-list-item input:checked:before,
.task-list-item input[checked]:before{
	color: inherit;
}
.md-tag {
	color: inherit;
	font: inherit;
}
#write pre.md-meta-block {
	min-height: 35px;
	padding: 0.5em 1em;
}
#write pre.md-meta-block {
	white-space: pre;
	background: #f8f8f8;
	border: 0px;
	color: #999;
	
	width: 100vw;
	max-width: calc(100% + 60px);
	margin-left: -30px;
	border-left: 30px #f8f8f8 solid;
	border-right: 30px #f8f8f8 solid;

	margin-bottom: 2em;
	margin-top: -1.3333333333333rem;
	padding-top: 26px;
	padding-bottom: 10px;
	line-height: 1.8em;
	font-size: 0.9em;
	font-size: 0.76em;
	padding-left: 0;
}
.md-img-error.md-image>.md-meta{
	vertical-align: bottom;
}
#write>h5.md-focus:before {
	top: 2px;
}

.md-toc {
	margin-top: 40px;
}

.md-toc-content {
	padding-bottom: 20px;
}

.outline-expander:before {
	color: inherit;
	font-size: 14px;
	top: auto;
	content: "\f0da";
	font-family: FontAwesome;
}

.outline-expander:hover:before,
.outline-item-open>.outline-item>.outline-expander:before {
  	content: "\f0d7";
}

/** source code mode */
#typora-source {
	font-family: Courier, monospace;
    color: #6A6A6A;
}

.cm-s-typora-default .cm-header, 
.cm-s-typora-default .cm-property,
.CodeMirror.cm-s-typora-default div.CodeMirror-cursor {
	color: #428bca;
}

.cm-s-typora-default .cm-atom, .cm-s-typora-default .cm-number {
	color: #777777;
}



</style>
</head>
<body class='typora-export' >
<div  id='write'  class = 'is-mac'><h1><a name='header-c5' class='md-header-anchor '></a>计算机组成原理笔记</h1><p>作者: 李根灵</p><p>声明: 自由转载-非商用-非衍生-保持署名（创意共享3.0许可证）</p><h2><a name='header-c11' class='md-header-anchor '></a>第一章</h2><h3><a name='header-c12' class='md-header-anchor '></a>处理器结构体系</h3><h4><a name='header-c13' class='md-header-anchor '></a>哈佛结构</h4><p><img src='/Users/absinthevoid/Documents/picture/Harvard_architecture.png' alt='Harvard_architecture' /></p><p><strong>哈佛架构</strong>（英语：<strong>Harvard architecture</strong>）是一种将程序指令储存和数据储存分开的存储器结构(Split Cache)。</p><p>中央处理器首先到程序指令储存器中读取程序指令内容，解码后得到数据地址，再到相应的数据储存器中读取数据，并进行下一步的操作（通常是执行）。程序指令储存和数据储存分开，数据和指令的储存可以同时进行，可以使指令和数据有不同的数据宽度。</p><p>哈佛架构的微处理器通常具有较高的执行效率。其程序指令和数据指令分开组织和储存的，执行时可以预先读取下一条指令。</p><h4><a name='header-c22' class='md-header-anchor '></a>冯·诺伊曼结构</h4><p><img src='/Users/absinthevoid/Documents/picture/560px-Von_Neumann_architecture.svg.png' alt='560px-Von_Neumann_architecture.svg' /></p><p><strong>冯·诺伊曼结构</strong>是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置，因此程序指令和数据的宽度相同。</p><p>冯.诺依曼结构处理器具有以下几个特点：</p><p>1：必须有一个存储器；2：必须有一个控制器；3：必须有一个运算器，用于完成算术运算和逻辑运算；4：必须有输入设备和输出设备，用于进行人机通信。:另外，程序和数据统一存储并在程序控制下自动工作。</p><p>存储程序计算机在体系结构上主要特点有：</p><ol start='' ><li>以运算单元为中心</li><li>采用存储程序原理</li><li>存储器是按地址访问、线性编址的空间</li><li>控制流由指令流产生</li><li>指令由操作码和地址码组成</li><li>数据以二进制编码</li></ol><h3><a name='header-c52' class='md-header-anchor '></a>指令集体系</h3><h4><a name='header-c53' class='md-header-anchor '></a>复杂指令集</h4><p>复杂指令集：(Complex Instruction Set Computing；缩写：CISC）是一种微处理器指令集架构，每个指令可执行若干低阶操作，诸如从记忆体读取、储存、和计算操作，全部集于单一指令之中。与之相对的是精简指令集。</p><p>在CISC微处理器中，程序的各条指令是按顺序串行执行的，每条指令中的各个操作也是按顺序串行执行的。顺序执行的优点是控制简单，但计算机各部分的利用率不高，执行速度慢。</p><h4><a name='header-c58' class='md-header-anchor '></a>精简指令集</h4><p><strong>精简指令集计算</strong>（英语：<strong>reduced instruction set computing</strong>，缩写：<strong>RISC</strong>）或简译为<strong>精简指令集</strong>，是计算机中央處理器的一种设计模式。这种设计思路可以想像成是一家流水線工廠，对指令数目和寻址方式都做了精简，使其实现更容易，指令并行执行程度更好，编译器的效率更高。</p><h4><a name='header-c61' class='md-header-anchor '></a>区别</h4><p>从硬件角度来看CISC处理的是不等长指令集，它必须对不等长指令进行分割，因此在执行单一指令的时候需要进行较多的处理工作。而RISC执行的是等长精简指令集，CPU在执行指令的时候速度较快且性能稳定。因此在并行处理方面RISC明显优于CISC，RISC可同时执行多条指令，它可将一条指令分割成若干个进程或线程，交由多个处理器同时执行。由于RISC执行的是精简指令集，所以它的制造工艺简单且成本低廉。</p><pre class='md-fences mock-cm' style='display:block;position:relative'>泡1杯茶
复杂指令集：1、去泡茶；2、哥，茶泡来了；精简指令集：1、去；2、拿杯子；3、放茶叶；4、泡茶；5、拿来。
显然复杂指令速度快效率高；</pre><pre class='md-fences mock-cm' style='display:block;position:relative'>泡50杯茶
复杂指令集：1、去泡茶；2、哥，茶泡来了；3、去泡茶；4、哥，茶泡来了；5、去泡茶；6、哥，茶泡来了；7、去泡茶；8、哥，茶泡来了......重复道50次。
精简指令集：1、去；2、拿杯子*50，3、放茶叶*50,4、泡茶*50,5、拿来。
精简指令集效率高耗能少</pre><p>在执行高密度的运算任务的时候CISC就更具备优势，而在执行简单重复劳动的时候RISC就能占到上风。</p><h3><a name='header-c68' class='md-header-anchor '></a>总线</h3><p>总线（Bus）是指计算机组件间规范化的交换数据（data）的方式，即以一种通用的方式为各组件提供数据传送和控制逻辑。从另一个角度来看，如果说主机板（Mother Board）是一座城市，那么总线就像是城市里的公共汽车（bus），能按照固定行车路线，传输来回不停运作的位元（bit）。这些线路在同一时间内都仅能负责传输一个位元。因此，必须同时采用多条线路才能传送更多资料，而总线可同时传输的资料数就称为宽度（width），以位元为单位，总线宽度愈大，传输效能就愈佳。总线的频宽（即单位时间内可以传输的总资料数）为：总线频宽 = 频率x宽度（Bytes/sec。</p><p>PC上一般有五种总线：</p><blockquote><p>数据总线（Data Bus）：在CPU与RAM之间来回传送需要处理或是需要储存的数据。
地址总线（Address Bus）：用来指定在RAM（Random Access Memory）之中储存的数据的地址。
控制总线（Control Bus）：将微处理器控制单元（Control Unit）的信号，传送到周边装置，一般常见的为USB Bus和1394 Bus。
扩展总线（Expansion Bus）：可连接扩展槽和电脑。
局部总线（Local Bus）：取代更高速数据传输的扩展总线。</p></blockquote><h3><a name='header-c80' class='md-header-anchor '></a>寻址空间</h3><p>寻址空间一般指的是CPU对于内存寻址的能力。计算机的寻找范围由总线宽度（处理器的地址总线的位数）决定的，也可以理解为cpu寄存器位数，这二者一般是匹配的。</p><p>由此推出：地址总线为N位（N通常都是8的整数倍；也说N根数据总线）的CPU寻址范围是2的N次方字节，即2^N(B)。</p><h3><a name='header-c85' class='md-header-anchor '></a>中断与轮询</h3><h4><a name='header-c86' class='md-header-anchor '></a>轮询</h4><p>很多I/O设备都有一个状态寄存器，用于描述设备当前的工作状态，每当设备状态发生改变时，设备将修改相应状态寄存器位。通过不断查询设备的状态寄存器，CPU就可以了解设备的状态，从而进行必要的I/O操作。为了节约CPU资源，查询工作往往不是连续的，而是定时进行。 </p><p>轮询方式具有简单、易实现、易控制等优势，在很多小型系统中有大量应用。对那些实时敏感性不高、具有大量CPU资源的系统来说，轮询方式有很广泛的应用。最典型的用途就是在那些任务比较单一的单片机上，嵌入式系统中也有应用。 </p><h4><a name='header-c91' class='md-header-anchor '></a>中断</h4><p>中断，顾名思义，就是打断正在进行中的工作。中断不需要处理器轮询设备的状态，设备在自己发生状态改变时将主动发送一个信号给处理器（PIC），后者在接收到这一通知信号时，会挂起当前正在执行的任务转而去处理响应外设的中断请求。中断通知机制通过硬件信号异步唤起处理器的注意，解决了外部设备与处理器之间速度不匹配导致的资源浪费问题。 </p><p>现代设备绝大多数采用中断的方式与处理器进行沟通，因此设备驱动程序必须能够支持设备的中断特性。</p><h4><a name='header-c96' class='md-header-anchor '></a>中断向量表</h4><p>在存储器地址空间中，规定最低的1K空间，即00000H到003FFH为中断向量表。全表共含256个中断向量，每个向量的长度为4字节，包含中断处理程序的起始地址。共有从0到255共256个中断类型码，每个中断类型码对应的中断向量所在地址为该类型码乘以4。举例而言，如果中断类型码为1，则对应中断向量所在地址为00004H；如果中断类型码为33，则对应中断向量所在地址为00084H。这样，如果已知一个中断类型码，则需要通过两次地址转换（中断类型码到中断向量表地址；中断向量表地址到中断处理程序地址）才能到达中断处理程序。另外应注意每一个中断向量所包含的地址是以低二字节存储偏移量，高二字节存储段地址的形式存储目标地址值的。</p><p>在全部256个中断中，前32个（0—31）为硬件系统所预留。后224个可由用户设定。</p><p>在INTEL后续的32位CPU中，使用中断描述符表来代替中断向量表。中断描述符表的起始地址由中断描述符表寄存器（IDTR）来定位，因此不再限于底部1K位置。</p><h4><a name='header-c103' class='md-header-anchor '></a>上下文交换</h4><p>上下文交换(英语：context switch)，又称环境切换，是一个储存和重建CPU的状态 (内文)，因此令多个进程(process)可以分享单一CPU资源的计算过程。要交换CPU上的进程时，必需先行储存目前进程的状态，再将欲执行的进程之状态读回CPU中。</p><p>在一次交换中，第一个行程的状态要被纪录在某个地方，这样当排程器(scheduler)要回到这个行程时，才可以重建这个行程并且继续运算。</p><p>这里所谓「行程的状态」，包含了这个行程使用的所有暂存器(register)，特别是程式计数器；加上所有作业系统可能需要的特定资料。这些资料一般以名为行程控制表(process control block，PCB)的资料结构储存起来。</p><h2><a name='header-c110' class='md-header-anchor '></a>第二章</h2><h3><a name='header-c111' class='md-header-anchor '></a>寄存器</h3><h4><a name='header-c112' class='md-header-anchor '></a>寄存器概念</h4><p>寄存器（Register），是中央处理器内的其中组成部份。寄存器是有限存贮容量的高速存贮部件，它们可用来暂存指令、数据和位址。在中央处理器的控制部件中，包含的寄存器有指令寄存器（IR）和程序计数器。在中央处理器的算术及逻辑部件中，包含的寄存器有累加器。</p><h4><a name='header-c115' class='md-header-anchor '></a>端模式</h4><p>如果将一个32位的整数0x12345678存放到一个整型变量（int）中，这个整型变量采用大端或者小端模式在内存中的存储由下表所示。为简单起见，本文使用OP0表示一个32位数据的最高字节MSB（Most Significant Byte），使用OP3表示一个32位数据最低字节LSB（Least Significant Byte）。 </p><table><thead><tr><th>地址偏移</th><th>大端模式</th><th>小端模式</th></tr></thead><tbody><tr><td>0x00</td><td>12（OP0）</td><td>78（OP3）</td></tr><tr><td>0x01</td><td>34（OP1）</td><td>56（OP2）</td></tr><tr><td>0x02</td><td>56（OP2）</td><td>34（OP1）</td></tr><tr><td>0x03</td><td>78（OP3）</td><td>12（OP0）</td></tr></tbody></table><p>大端：较高的有效字节存放在较低的存储器地址，较低的有效字节存放在较高的存储器地址。</p><p>小端：较高的有效字节存放在较高的的存储器地址，较低的有效字节存放在较低的存储器地址。</p><p>有的处理器系统采用了小端方式进行数据存放，如Intel的奔腾。有的处理器系统采用了大端方式进行数据存放，如IBM半导体和Freescale的PowerPC处理器</p><h3><a name='header-c145' class='md-header-anchor '></a>移位操作</h3><h4><a name='header-c146' class='md-header-anchor '></a>逻辑移位</h4><p>逻辑移位（不管是左移位还是右移位），都是空缺处补0 。</p><h4><a name='header-c149' class='md-header-anchor '></a>算术移位</h4><p>要保证符号位的不改变（逻辑左移位补0,   逻辑右移位看符号位）。</p><h4><a name='header-c152' class='md-header-anchor '></a>实例</h4><p>假设对数字5进行移位操作，并且数字5被存在了一个8位变量中。</p><p>那么对于5，也就是0000 0101，如果把整个二进制串向左移动一位，会发生什么？ 最左边的0会移出存储范围，也就是说那个0会被丢掉；最右边会空下，空下的位计算机自然默认它是0，新的串变成了0000 1010，这个数是多少呢？10，也就是5*2。 也就是说，把某个数左移1位就等价于把那个数乘2。</p><p>当然，这样的话，如果把某个数左移2位，也就是做两次“左移1位”，也就等价于把那个数乘2再乘2，也就是乘4。扩展到n，也就是<strong>左移n位等价于把那个数乘2的n次方</strong>。当然如果溢出了就不等于了，目前主要讨论在没有溢出的情况下。 再来看右移，再拿5举例，0000 0101，如果我把整个二进制串向右移动一位，最右边的1会因为移出了存储范围被丢掉，最左边的空位会被认为是0，也就是这个串变成了：0000 0010–&gt;2。这也就说明，把某个数右移1位，就等价于把那个数整除2，于是，<strong>右移n位也等价于把那个数整除以（2的n次方）</strong>。</p><p>但是，刚刚讨论的东西是针对非负数的，当把左移右移应用到负数时，事情会发生改变。 首先来看左移，比如-5，在8位存储中，因为使用了补码，-5的二进制表示为1111 1011，左移一位，最左边第一位被移出去一个1，但是符号位又被来自第二位的1填上了，最右边空位被当做0，也就是变成1111 0110–&gt;-10，对于左移而言，负数似乎是没问题的， 然后来看右移，比如-5，1111 1011，右移1位，最左位因为空出来了会被认为是0，这样左移的结果就是0111 1101–&gt;125。明明是负数，右移了一下就变成正数了。</p><p>但是有时，用户使用移位指令想完成的其实只是“大小的缩放”而不是“突然就把负数移成正数了”，在这样的情况下，必须保持符号位不变，于是就发明了算术移位： 算术移位对于左移不用做改动，因为左移时，最高位自动被这个数的第二高位填上了，如果左移之后符号改变，说明数超出了存储范围，发生了溢出。（例如0111 1111左移1位变成了1111 1110，符号如果不溢出，移位仍然是对的。 而对于右移时，因为最高位符号位的数被移走了，所以为了保持符号不变，原来符号位是多少，最高位空位就应该填入多少，也就是说像这样：</p><p><img src='/Users/absinthevoid/Documents/picture/300px-Rotate_right_arithmetically.svg.png' alt='300px-Rotate_right_arithmetically.svg' /></p><h3><a name='header-c165' class='md-header-anchor '></a>整数的表示</h3><h4><a name='header-c166' class='md-header-anchor '></a>无符号数与有符号数</h4><p>无符号数：不存在正负之分，所有位都用来表示数的本身。</p><p>有符号数：最高位用来表示数的正负，最高位为1则表示负数，最高位为0则表示正数。</p><h5><a name='header-c171' class='md-header-anchor '></a>无符号数转有符号数</h5><p>看无符号数的最高位是否为1，如果不为1（为0），则有符号数就直接等于无符号数；如果无符号数的最高位为1，则将无符号数取补码，得到的数就是有符号数。</p><h5><a name='header-c174' class='md-header-anchor '></a>有符号数转无符号数</h5><p>看有符号数的最高位是否为1，如果不为1（为0），则无符号数就直接等于有符号数；如果有符号数的最高位为1，则将有符号数取补码，得到的数就是无符号数。</p><p>总结转换规律：有符号数与无符号数之间的转换，都要看要转换的数的最高位是否为1，如果不为1，则转换结果就是要转换的数的本身；如果为1，则转换结果就是转换的数（看作是负数）的补码。</p><h4><a name='header-c179' class='md-header-anchor '></a>反码表示法</h4><p>反码的表示方法是:</p><p>正数的反码是其本身</p><p>负数的反码是在其原码的基础上, 符号位不变，其余各个位取反.</p><pre class='md-fences mock-cm' style='display:block;position:relative'>[+1] = [00000001]原 = [00000001]反

[-1] = [10000001]原 = [11111110]反</pre><h4><a name='header-c187' class='md-header-anchor '></a>补码表示法</h4><p>补码的表示方法是:</p><p>正数的补码就是其本身</p><p>负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)</p><pre class='md-fences mock-cm' style='display:block;position:relative'>[+1] = [00000001]原 = [00000001]反 = [00000001]补

[-1] = [10000001]原 = [11111110]反 = [11111111]补</pre><h4><a name='header-c195' class='md-header-anchor '></a>为什么要使用补码</h4><p>首先来看原码:</p><p>计算十进制的表达式: 1-1=0</p><pre class='md-fences mock-cm' style='display:block;position:relative'>1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2</pre><p>如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.</p><p>为了解决原码做减法的问题, 出现了反码:</p><p>计算十进制的表达式: 1-1=0</p><pre class='md-fences mock-cm' style='display:block;position:relative'>1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0</pre><p>发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在&quot;0&quot;这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.</p><p>于是补码的出现, 解决了0的符号以及两个编码的问题:</p><pre class='md-fences mock-cm' style='display:block;position:relative'>1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原</pre><p>这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:</p><pre class='md-fences mock-cm' style='display:block;position:relative'>(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补</pre><p>-1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)</p><p>使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].</p><p>因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-2^31, 2^31-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.</p><h4><a name='header-c222' class='md-header-anchor '></a>有符号数和无符号数的比较</h4><p>首先介绍C语言中的<strong>整数自动转换原则</strong>：</p><p>当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为<strong>无符号类型</strong>。因此，从这个意义上讲，无符号数的运算优先级要高于有符号数，这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。 </p><p>而对于浮点数来说，浮点数（float，double）实际上都是有符号数，unsigned 和signed前缀不能加在float和double之上，当然就不存在有符号数根无符号数之间转化的问题了。</p><h5><a name='header-c229' class='md-header-anchor '></a>一个示例实验</h5><p>在C语言中，分别定义一个signed int型数据和unsigned int型数据，然后进行大小比较：</p><pre class="md-fences md-end-block" lang="c++"> <div class="CodeMirror cm-s-inner CodeMirror-wrap"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"></div><div class="CodeMirror-hscrollbar" style="left: 0px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="min-width: 18px;"><div style="min-width: 1px; height: 0px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; min-height: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">unsigned</span> <span class="cm-variable-3">int</span> <span class="cm-variable">a</span> <span class="cm-operator">=</span> <span class="cm-number">20</span>;</span></pre></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">signed</span> <span class="cm-variable-3">int</span> <span class="cm-variable">b</span> <span class="cm-operator">=</span> <span class="cm-operator">-</span><span class="cm-number">130</span>;</span></pre></div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 0px;"></div><div class="CodeMirror-gutters" style="display: none; height: 52px;"></div></div></div></pre><p>实验证明b&gt;a，也就是说-130 &gt; 20,为什么会出现这样的结果呢？</p><p>这是因为在C语言操作中，如果遇到无符号数与有符号数之间的操作，编译器会自动转化为无符号数来进行处理，因此a＝20，b＝4294967166，这样比较下去当然b&gt;a了。</p><h5><a name='header-c237' class='md-header-anchor '></a>再举一个例子</h5><pre class="md-fences md-end-block" lang="c++"> <div class="CodeMirror cm-s-inner CodeMirror-wrap"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"></div><div class="CodeMirror-hscrollbar" style="left: 0px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="min-width: 18px;"><div style="min-width: 1px; height: 0px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; min-height: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">unsigned</span> <span class="cm-variable-3">int</span> <span class="cm-variable">a</span> <span class="cm-operator">=</span> <span class="cm-number">20</span>;</span></pre></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">signed</span> <span class="cm-variable-3">int</span> <span class="cm-variable">b</span> <span class="cm-operator">=</span> <span class="cm-operator">-</span><span class="cm-number">130</span>;</span></pre><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable">std::cout</span> <span class="cm-operator">&lt;&lt;</span> <span class="cm-variable">a</span> <span class="cm-operator">+</span> <span class="cm-variable">b</span> <span class="cm-operator">&lt;&lt;</span><span class="cm-variable">std::endl</span>;</span></pre></div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 0px;"></div><div class="CodeMirror-gutters" style="display: none; height: 78px;"></div></div></div></pre><p>结果输出为4294967186，同样的道理，在运算之前，a＝20，b被转化为4294967166，所以a＋b＝4294967186。</p><h3><a name='header-c241' class='md-header-anchor '></a>浮点数的表示</h3><h4><a name='header-c242' class='md-header-anchor '></a>IEEE 754</h4><p>IEEE二进位浮点数算术标准（IEEE 754）是20世纪80年代以来最广泛使用的浮点数运算标准，为许多CPU与浮点运算器所採用。这个标準定义了表示浮点数的格式（包括负零-0）与反常值（denormal number）），一些特殊数值（无穷（Inf）与非数值（NaN）），以及这些数值的「浮点数运算子」；它也指明了四种数值修约规则和五种例外状况（包括例外发生的时机与处理方式）。</p><p>根据国际标准IEEE 754，任意一个二进制浮点数V可以表示成下面的形式：</p><p><img src='/Users/absinthevoid/Documents/picture/chart.png' alt='chart' /></p><p><strong>（1）(-1)^s表示符号位，当s=0，V为正数；当s=1，V为负数。</strong></p><p><strong>（2）M表示有效数字，大于等于1，小于2。</strong></p><p><strong>（3）2^E表示指数位。</strong></p><p>举例来说，十进制的5.0，写成二进制是101.0，相当于1.01×2^2。那么，按照上面V的格式，可以得出s=0，M=1.01，E=2。</p><p>十进制的-5.0，写成二进制是-101.0，相当于-1.01×2^2。那么，s=1，M=1.01，E=2。</p><p>IEEE 754规定，对于32位的浮点数，最高的1位是符号位s，接着的8位是指数E，剩下的23位为有效数字M。</p><p><img src='/Users/absinthevoid/Documents/picture/bg2010060601.png' alt='bg2010060601' /></p><p>对于64位的浮点数，最高的1位是符号位S，接着的11位是指数E，剩下的52位为有效数字M。</p><p><img src='/Users/absinthevoid/Documents/picture/bg2010060602.png' alt='bg2010060602' /></p><p>IEEE 754对有效数字M和指数E，还有一些特别规定。</p><p>前面说过，1≤M&lt;2，也就是说，M可以写成1.xxxxxx的形式，其中xxxxxx表示小数部分。<strong>IEEE 754规定，在计算机内部保存M时，默认这个数的第一位总是1，因此可以被舍去，只保存后面的xxxxxx部分。</strong>比如保存1.01的时候，只保存01，等到读取的时候，再把第一位的1加上去。这样做的目的，是节省1位有效数字。以32位浮点数为例，留给M只有23位，将第一位的1舍去以后，等于可以保存24位有效数字。</p><p>至于指数E，情况就比较复杂。</p><p>首先，E为一个无符号整数（unsigned int）。这意味着，如果E为8位，它的取值范围为0~255；如果E为11位，它的取值范围为0~2047。但是，我们知道，科学计数法中的E是可以出现负数的，<strong>所以IEEE 754规定，E的真实值必须再减去一个中间数，对于8位的E，这个中间数是127；对于11位的E，这个中间数是1023。</strong></p><p>比如，2^10的E是10，所以保存成32位浮点数时，必须保存成10+127=137，即10001001。</p><p>然后，指数E还可以再分成三种情况：</p><p><strong>（1）E不全为0或不全为1。</strong>这时，浮点数就采用上面的规则表示，即指数E的计算值减去127（或1023），得到真实值，再将有效数字M前加上第一位的1。</p><p><strong>（2）E全为0。</strong>这时，浮点数的指数E等于1-127（或者1-1023），有效数字M不再加上第一位的1，而是还原为0.xxxxxx的小数。这样做是为了表示±0，以及接近于0的很小的数字。</p><p><strong>（3）E全为1。</strong>这时，如果有效数字M全为0，表示±无穷大（正负取决于符号位s）；如果有效数字M不全为0，表示这个数不是一个数（NaN）。</p><p>任何有效数上的运算结果，通常都存放在较长的暂存器中，当结果被放回浮点格式时，必须将多出来的位元丢弃。 有多种方法可以用来执行捨入作业，实际上IEEE标準列出4种不同的方法：</p><p>舍入到最接近：舍入到最接近，在一样接近的情况下偶数优先（Ties To Even，这是默认的舍入方式）：会将结果舍入为最接近且可以表示的值，但是当存在两个数一样接近的时候，则取其中的偶数（在二进制中式以0结尾的）。</p><p>朝+∞方向捨入：会将结果朝正无限大的方向捨入。</p><p>朝-∞方向捨入：会将结果朝负无限大的方向捨入。</p><p>朝0方向捨入：会将结果朝0的方向捨入。</p><h4><a name='header-c295' class='md-header-anchor '></a>浮点数表示示例</h4><p><strong>请问浮点数9.0，如何用二进制表示？还原成十进制又是多少？</strong></p><p>首先，浮点数9.0等于二进制的1001.0，即1.001×2^3。</p><p>那么，第一位的符号位s=0，有效数字M等于001后面再加20个0，凑满23位，指数E等于3+127=130，即10000010。</p><p>所以，写成二进制形式，应该是s+E+M，即0 10000010 001 0000 0000 0000 0000 0000。</p><p>再举一个例子，转换15到浮点数：</p><p><img src='/Users/absinthevoid/Documents/picture/Screen%20Shot%202017-06-11%20at%2011.23.08%20PM.png' alt='Screen Shot 2017-06-11 at 11.23.08 PM' /></p><h4><a name='header-c308' class='md-header-anchor '></a>双精度与单精度浮点数</h4><p><img src='/Users/absinthevoid/Documents/picture/Screen%20Shot%202017-06-12%20at%2012.41.24%20PM.png' alt='Screen Shot 2017-06-12 at 12.41.24 PM' /></p><p></p><h2><a name='header-c313' class='md-header-anchor '></a>第三章</h2><h3><a name='header-c314' class='md-header-anchor '></a>编译器，汇编器和链接器</h3><p>通常情况下，C程序的构建过程包括四个阶段，分别采用不同的“工具”，如预处理器，编译器，汇编器和链接器。在最后应该有一个单一的可执行文件。</p><ul><li><strong>预处理</strong>：它处理头文件，条件编译指令和宏。</li><li><strong>编译</strong>：它需要预处理器的输出、源代码，并生成汇编源代码。</li><li><strong>汇编</strong>：它采用汇编源代码，并生成带偏移地址的汇编清单。汇编器的输出存储在目标文件。</li><li><strong>链接</strong>：编译的最后阶段。这需要一个或多个目标文件或库作为输入，并结合他们产生一种单一的（通常是可执行文件）文件。在这样做时，它解析引用外部符号，分配给最后地址的程序/函数和变量，并修改代码和数据，以反映新的地址（一个称为重定位的处理）。</li></ul><p><img src='/Users/absinthevoid/Documents/picture/s1tpeSbh3kLRw8GquOYQNjQ.png' alt='s1tpeSbh3kLRw8GquOYQNjQ' /></p><p>下面的一张图给出了参与构建C程序，从编译开始，直到加载可执行文件成为内存中运行的程序（一个进程）的步骤。</p><p><img src='/Users/absinthevoid/Documents/picture/sSX3-yqGU_GmC3HqvKc1K0A.png' alt='sSX3-yqGU_GmC3HqvKc1K0A' /></p><h3><a name='header-c336' class='md-header-anchor '></a>目标文件和可执行文件 OBJECT FILES and EXECUTABLE</h3><ul><li>在源代码被汇编后，会得到很多目标文件(Object File ,如 .o .obj ) ，然后通过连接得到一个可执行的文件。</li><li>可目标文件和可执行文件的格式有好多种，例如像ELF(Executable and Linking Forma)和COFF(Common Object-File Format). ELF是Linux系统中使用的。</li><li>目标文件的里的内容有段区域。这些段区域可容纳可执行代码，数据，动态链接信息，调试数据，符号表，重定位信息，注释，字符串表，以及附注。</li><li>部分段会被加载到进程映像，另外一些段会提供一些必要的信息来帮助构建进程，同时还有一些仅用于连接目标文件。</li><li>有几个部分是所有可执行文件格式共同的（可能有不同的名称，这取决于编译器/链接）如下表所示：</li></ul><p><img src='/Users/absinthevoid/Documents/picture/se83ohWk_SO6zZZE5LKOwog.png' alt='se83ohWk_SO6zZZE5LKOwog' /></p><h3><a name='header-c355' class='md-header-anchor '></a>链接器符号</h3><p>静态链接器的工作主要分为两个阶段：符号解析和重定位。</p><p>为创建可执行文件，静态链接器必须要完成的主要任务：</p><ol start='' ><li><strong>符号解析</strong>：把目标文件中符号的定义和引用联系起来;</li><li><strong>重定位</strong>：把符号定义和内存地址对应起来，然后修改所有对符号的引用。</li></ol><h4><a name='header-c367' class='md-header-anchor '></a>符号分类</h4><p>符号有如下三种：</p><ul><li>全局符号：非静态全局变量，非静态函数</li><li>外部符号：定义于其它模块，而被本模块引用的全局变量和函数</li><li>本地符号：静态变量(包括全局和局部)，静态函数</li></ul><p>对于静态局部变量，编译器会为其生成唯一的名字。如x.fun1，x.fun2。本地符号对链接器来说是不可见的。</p><h4><a name='header-c382' class='md-header-anchor '></a>符号决议</h4><p>当编译器遇到一个不是本模块定义的符号时，会假设该函数由其它模块定义，并生成一个链接器符号表条目，交由链接器处理。如果链接器在它的任何输入模块都没有找到该符号，会给出一个类似<code>undefined reference to &#39;xxx&#39;</code>的链接错误。而如果链接器在输入模块中找到了一个以上的外部符号定义，这个时候就需要链接器进行符号决议，链接器对多个外部符号定义可能并不报错甚至警告，而是按照它的规则去选择其中一个符号定义。</p><p>链接器将各个模块输出的全局符号，分类为<strong>强符号</strong>和<strong>弱符号</strong>：</p><ul><li>强符号：函数和已初始化的全局变量</li><li>弱符号：未初始化全局变量</li></ul><p>根据强弱符号的定义，链接器按照下面的规则处理多重定义的符号：</p><ul><li>规则1：不允许有多个强符号定义</li><li>规则2：如果有一个强符号和多个弱符号，那么选择强符号</li><li>规则3：如果有多个弱符号，那么从这些弱符号中选择sizeof大的那个，如果大小相同，则选择先链接的那个</li></ul><p>上面的规则是很多链接错误的根源，因为编译器在决议时可能默默地替你作出了决定，你并不知晓。根据上面的规则，可以引出下面几个经典例子：</p><p>源文件 lib.c</p><pre class="md-fences md-end-block" lang="c"> <div class="CodeMirror cm-s-inner CodeMirror-wrap"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"></div><div class="CodeMirror-hscrollbar" style="left: 0px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="min-width: 18px;"><div style="min-width: 1px; height: 0px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; min-height: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">int</span> <span class="cm-variable">x</span>;</span></pre></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">void</span> <span class="cm-def">f</span>()</span></pre><pre class=""><span style="padding-right: 0.1px;">{</span></pre><pre class=""><span style="padding-right: 0.1px;"> &nbsp;  <span class="cm-variable">x</span> <span class="cm-operator">=</span> <span class="cm-number">1235</span>;</span></pre><pre class=""><span style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 0px;"></div><div class="CodeMirror-gutters" style="display: none; height: 130px;"></div></div></div></pre><p>源文件 main.c</p><pre class="md-fences md-end-block" lang="c"> <div class="CodeMirror cm-s-inner CodeMirror-wrap"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"></div><div class="CodeMirror-hscrollbar" style="left: 0px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="min-width: 18px;"><div style="min-width: 1px; height: 0px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; min-height: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><pre class=""><span style="padding-right: 0.1px;"><span class="cm-meta">#include&lt;stdio.h&gt;</span></span></pre></div><pre class=""><span style="padding-right: 0.1px;"><span>​</span></span></pre><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">void</span> <span class="cm-def">f</span>(<span class="cm-variable-3">void</span>);</span></pre><pre class=""><span style="padding-right: 0.1px;"><span>​</span></span></pre><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">int</span> <span class="cm-variable">x</span> <span class="cm-operator">=</span> <span class="cm-number">1234</span>;</span></pre><pre class=""><span style="padding-right: 0.1px;"><span>​</span></span></pre><pre class=""><span style="padding-right: 0.1px;"><span class="cm-variable-3">int</span> <span class="cm-def">main</span>(<span class="cm-variable-3">void</span>)</span></pre><pre class=""><span style="padding-right: 0.1px;">{</span></pre><pre class=""><span style="padding-right: 0.1px;"> &nbsp;  <span class="cm-variable">f</span>();</span></pre><pre class=""><span style="padding-right: 0.1px;"> &nbsp;  <span class="cm-variable">printf</span>(<span class="cm-string">"x=%d\n"</span>, <span class="cm-variable">x</span>);</span></pre><pre class=""><span style="padding-right: 0.1px;"> &nbsp;  <span class="cm-keyword">return</span> <span class="cm-number">0</span>;</span></pre><pre class=""><span style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 0px;"></div><div class="CodeMirror-gutters" style="display: none; height: 312px;"></div></div></div></pre><p>上面的代码中，main函数printf输出： <code>x=1235</code>。因为链接器通过规则2决议符号x的定义为main.c中的强符号定义，而lib.c的作者并不知情，他对x的使用和修改影响到了main.c。这种交互修改，相互影响将会很复杂，因为大家都以为自己在做对的事情，在用对的变量。而整个决议过程，链接器悄无声息地完成了。</p><h4><a name='header-c416' class='md-header-anchor '></a>总结</h4><p>由于符号决议容易引发的种种问题，我们在写C的时候应注意：</p><ul><li>尽量用static属性隐藏变量和函数在模块内的声明，就像在C++中尽量用private保护类私有成员一样。</li><li>少定义弱符号，尽量初始化全局变量，这样链接器会根据规则1给出多个符号定义的错误。</li><li>为链接器设置必要选项，如gcc的 -fno-common，这样在遇到多重符号定义时，链接器会给出警告。</li></ul><h4><a name='header-c429' class='md-header-anchor '></a>C++的符号决议</h4><p>C++并不支持强弱符号同时存在，所有符号都只能有一个定义(函数重载通过改写函数符号来确保其唯一)，因此在很大程度上避免了C中的链接器困扰。</p><h3><a name='header-c432' class='md-header-anchor '></a>链接器重定位</h3><p>编译器和汇编器生产从地址零开始的代码和数据节。链接器通过把每个符号定义与一个存储器地址联系起来，然后修改所有对这些符号的引用，使得它们指向这个存储器地址，从而重定位这些节。</p><p>在这里首先说明静态链接的问题：</p><p>静态链接器的输入是一组可重定向文件，输出一个全链接的可执行目标文件。 
目标文件有三种形式： </p><ol start='' ><li>可重定向目标文件：包含二进制代码和数据，可以在编译时和其他可重定向目标文件一起，得到可执行文件。 </li><li>可执行目标文件：包含二进制代码和数据，可以直接拷贝进内存进行执行。 </li><li>共享目标文件：一种特殊的重定向文件，可以被加载进内存，并在加载和运行期间进行动态链接。</li></ol><h4><a name='header-c450' class='md-header-anchor '></a>使用静态库进行解析的过程</h4><p>在编译完函数后，符号表中会出现很多undef的符号，记为U. D 表示已经定义的符号， E表示一组可重定向的文件， 是链接时需要merge的静态库文件。 </p><p>执行的顺序如下：</p><p>按照给出的静态库的顺序扫描； </p><p>扫描一个静态库，看有没有匹配U中的符号，如果匹配， 则将该符号放入D中，修改相关信息。将链接的该块的无法解析的符号加入U中。</p><p>这样存在的最大问题是循环依赖。因此链接的顺序是很重要的。</p><h4><a name='header-c461' class='md-header-anchor '></a>动态链接</h4><p>在此种方式下，函数的定义在动态链接库或共享对象的目标文件中。<strong>在编译的链接阶段，动态链接库只提供符号表和其他少量信息用于保证所有符号引用都有定义，保证编译顺利通过。动态链接器(ld-linux.so)链接程序在运行过程中根据记录的共享对象的符号定义来动态加载共享库，然后完成重定位。</strong>在此可执行文件被执行时，动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。</p><h3><a name='header-c464' class='md-header-anchor '></a> </h3></div>
</body>
</html>